﻿using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;

namespace NetfractionHub.Security
{
    public class Permission
    {
        /// <summary>
        /// Attempts to parse the <paramref name="permission"/> string into a member of the AccessPermission enumeration.
        /// </summary>
        /// <param name="permission">The string name of the permission to parse.</param>
        /// <param name="accessPermission">The variable to hold the parsed AccessPermission.</param>
        /// <returns>True if parsing succeeds. False if there is an exception.</returns>
        /*public static bool TryParse(string permission, out AccessPermission accessPermission)
        {
            accessPermission = AccessPermission.None;
            try
            {
                accessPermission = (AccessPermission)Enum.Parse(typeof(AccessPermission), permission, true);
                return true;
            }
            catch (ArgumentNullException)
            {
                return false;
            }
            catch (ArgumentException)
            {
                return false;
            }
        }*/

        /// <summary>
        /// Checks if the specified Identity has the required access permission.
        /// </summary>
        /// <param name="identity">The Identity to check.</param>
        /// <param name="permissionRequired">The requested access permission.</param>
        /// <returns>True if access is allowed, otherwise false.</returns>
        public static bool HasPermission(Identity identity, Type permissionType)
        {
            if (identity == null)
                return false;

            if (permissionType == null)
                return false;

            if (identity.Permissions.ContainsKey(permissionType))
                return identity.Permissions[permissionType] == AccessState.Allow;
            else if (identity.Role.Permissions.ContainsKey(permissionType))
                return identity.Role.Permissions[permissionType] == AccessState.Allow;
            else
                return false;
        }

        /*public static bool HasPermission(Identity identity, AccessPermissionBase permissionRequired)
        {
            if (identity.Permissions.ContainsKey(permissionRequired))
            {
                return identity.Permissions[permissionRequired] == AccessState.Allow;
            }
            else if (identity.Role.Permissions.ContainsKey(permissionRequired))
            {
                return identity.Role.Permissions[permissionRequired] == AccessState.Allow;
            }
            else
            {
                return false;
            }
        }*/

        /// <summary>
        /// Checks if the specified Role has the required access permission.
        /// </summary>
        /// <param name="role">The Role to check.</param>
        /// <param name="permissionRequired">The requested access permission.</param>
        /// <returns>True if access is allowed, otherwise false.</returns>
        public static bool HasPermission(Role role, Type permissionType)
        {
            //AccessPermissionBase permissionRequired = PermissionBuilder.Create(permissionType, AccessState.Allow);

            if (permissionType == null)
                return false;

            if (role == null)
                return false;

            if (role.Permissions.ContainsKey(permissionType))
                return role.Permissions[permissionType] == AccessState.Allow;

            return false;
        }

        /*public static bool HasPermission(Role role, AccessPermissionBase permissionRequired)
        {
            if (role == null)
            {
                return false;
            }

            if (role.Permissions.ContainsKey(permissionRequired))
            {
                return role.Permissions[permissionRequired] == AccessState.Allow;
            }
            return false;
        }*/

        /// <summary>
        /// Produces a list of all AccessPermission values.
        /// </summary>
        /// <returns>A list of all AccessPermission values, seperated by a new-line character.</returns>
        public static string ListAllPermissions()
        {
            StringBuilder sb = new StringBuilder();
            foreach (PermissionSourceData perm in PermissionSourceData.LoadPermissionSourceData())
            {
                if (perm.Source.CodeType == Netfraction.Hub.Scripting.SourceCodeType.BuiltIn)
                    sb.AppendFormat("{0} ({1})", perm.DisplayName, perm.Source.CodeType.ToString());
                else
                    sb.AppendFormat("{0} ({1}: {2})", perm.DisplayName, perm.Source.CodeType.ToString(), perm.Source.FileName);
                sb.AppendLine();
            }
            return sb.ToString();
        }

        /// <summary>
        /// Gets the differences in listX compared to listY.
        /// </summary>
        /// <param name="listX">A set of permissions.</param>
        /// <param name="listY">A set of permissions to compare to.</param>
        /// <returns>The permissions in listX that differ to those in listY.</returns>
        public static Dictionary<Type, AccessState> GetDifference(Dictionary<Type, AccessState> listX,
            Dictionary<Type, AccessState> listY)
        {
            Dictionary<Type, AccessState> resultList = new Dictionary<Type, AccessState>();
            foreach (KeyValuePair<Type, AccessState> xItem in listX)
            {
                if (listY.ContainsKey(xItem.Key))
                    if (listY[xItem.Key] != xItem.Value)
                        resultList.Add(xItem.Key, xItem.Value);
                else
                    resultList.Add(xItem.Key, xItem.Value);
            }
            return resultList;
        }

        /// <summary>
        /// Gets the combination of listX and listY, with listX member values overriding listY member values.
        /// </summary>
        /// <param name="listX"></param>
        /// <param name="listY"></param>
        /// <returns></returns>
        public static Dictionary<Type, AccessState> GetSuperimposition(Dictionary<Type, AccessState> listX,
            Dictionary<Type, AccessState> listY)
        {
            Dictionary<Type, AccessState> resultList = new Dictionary<Type, AccessState>();
            foreach (KeyValuePair<Type, AccessState> yItem in listY)
            {
                resultList.Add(yItem.Key, yItem.Value);
            }
            foreach (KeyValuePair<Type, AccessState> xItem in listX)
            {
                if (resultList.ContainsKey(xItem.Key))
                    resultList[xItem.Key] = xItem.Value;
                else
                    resultList.Add(xItem.Key, xItem.Value);
            }
            return resultList;
        }

        /// <summary>
        /// Returns a string to present to users when permission is denied for an operation.
        /// </summary>
        /// <param name="permission">The permission which was denied.</param>
        /// <returns>A string stating the given permission has been denied.</returns>
        public static string GetDeniedString(Type permissionType)
        {
            AccessPermissionBase permissionRequired = PermissionBuilder.Create(permissionType);

            if (permissionRequired == null)
                return string.Format("Unkown permission type '{0}'.", permissionType.FullName);

            return string.Format("Permission denied. Missing permission '{0}'.", permissionRequired.ToString());
        }
    }
}
